// 《围棋》作者版权所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package runtime

import (
	"runtime/internal/sys"
	"unsafe"
)

// libc函数包装器。必须在系统堆栈上运行。

// go:nosplit 
// go:cgo\u不安全参数
func g0_pthread_key_create(k *pthreadkey, destructor uintptr) int32 {
	return asmcgocall(unsafe.Pointer(funcPC(pthread_key_create_trampoline)), unsafe.Pointer(&k))
}
func pthread_key_create_trampoline()

// go:nosplit 
// go:cgo\u不安全参数
func g0_pthread_setspecific(k pthreadkey, value uintptr) int32 {
	return asmcgocall(unsafe.Pointer(funcPC(pthread_setspecific_trampoline)), unsafe.Pointer(&k))
}
func pthread_setspecific_trampoline()

// go cgo\u导入动态libc\u pthread\u键创建/usr/lib/libSystem.B.dylib“

// tlsinit为g分配一个线程本地存储插槽。
// 
// 它使用pthread_key_create查找第一个可用插槽，并使用
// 它作为runtime.tlsg的偏移量值。
// 
// 这在g0堆栈上启动时运行，但在设置g之前，因此它必须
// 不拆分堆栈（传递）。g预计为零，因此
// （例如asmcgocall）将跳过保存或读取g。
// 
// go:nosplit 
func tlsinit(tlsg *uintptr, tlsbase *[_PTHREAD_KEYS_MAX]uintptr) {
	var k pthreadkey
	err := g0_pthread_key_create(&k, 0)
	if err != 0 {
		abort()
	}

	const magic = 0xc476c475c47957
	err = g0_pthread_setspecific(k, magic)
	if err != 0 {
		abort()
	}

	for i, x := range tlsbase {
		if x == magic {
			*tlsg = uintptr(i * sys.PtrSize)
			g0_pthread_setspecific(k, 0)
			return
		}
	}
	abort()
}
